﻿using System;
using System.Collections.Generic;
using System.Configuration ;
using System.Linq;
using System.Linq.Expressions ;
using System.Text;
using System.Threading.Tasks;
using FreeSql;

namespace BoYuanCore.DBD
{
    public class DBServices
    {
        private static IFreeSql _instance = null;
        private static readonly object _instanceLock = new object();
        private static string _ConnectionString => "";//待完善

        /// <summary>          
        /// 获取实例(单例模式)        
        /// </summary>          
        /// <returns></returns>          
        public static IFreeSql GetInstance()
        {
            if (_instance == null)
                lock (_instanceLock)
                    if (_instance == null)
                    {
                        _instance = new FreeSql.FreeSqlBuilder()
                              .UseConnectionString(FreeSql.DataType.Sqlite, _ConnectionString)
                              .UseAutoSyncStructure(false) //自动同步实体结构到数据库
                              .Build(); //请务必定义成 Singleton 单例模式
                    }
            return _instance;
        }
        // FreeSqlAop功能在mvc项目里FreeSqlSetup方法来实现，本框架层不想注入log组件

        #region 获取实体 https://github.com/dotnetcore/FreeSql/wiki/%E6%9F%A5%E8%AF%A2

        /// <summary>z
        /// 获取一个实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id">主键</param>
        /// <returns></returns>
        public static T GetModel<T>(object id) where T : class
        {
            return GetInstance().Select<T>().WhereDynamic(id).First();
        }

        #endregion

        #region 添加 https://github.com/dotnetcore/FreeSql/wiki/%E6%B7%BB%E5%8A%A0
        //全部列 < 指定列(InsertColumns) < 忽略列(IgnoreColumns)

        /// <summary>
        /// 添加实体数据，并返回主键值(主键为long类型雪花id,实体需要设置主键特性),null值也会插入
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static long InsertModel<T>(T t) where T : class, new()
        {
            return GetInstance().Insert<T>(t).ExecuteIdentity();
        }

        /// <summary>
        /// 添加实体数据,并指定插入字段集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="insertColumns"></param>
        /// <returns></returns>
        public static long InsertModel<T>(T t, Expression<Func<T, object>> insertColumns) where T : class, new()
        {
           return GetInstance().Insert<T>(t).InsertColumns(insertColumns).ExecuteIdentity();
        }

        /// <summary>
        /// 插入一条，并忽略指定字段
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="ignoreColumns">要忽略的字段</param>
        /// <returns></returns>
        public static long InsertModel_Ignore<T>(T t, Expression<Func<T, object>> ignoreColumns) where T : class, new()
        {
            return GetInstance().Insert<T>(t).IgnoreColumns(ignoreColumns).ExecuteIdentity();
        }

        #endregion

        #region 更新 https://github.com/dotnetcore/FreeSql/wiki/%E4%BF%AE%E6%94%B9
        //> 全部列 < 指定列(Set/SetRaw) < 忽略列(IgnoreColumns) 

        /// <summary>
        /// 根据主键更新实体，返回影响条数(实体字段要有主键特性)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static int UpdateModels<T>(T t) where T : class, new()
        {
            return GetInstance().Update<T>().SetSource(t).ExecuteAffrows();
        }

        /// <summary>
        /// 根据主键更新实体(要指定更新的列)，返回影响条数(实体字段要有主键特性)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="columns"></param>
        /// <returns></returns>
        public static int UpdateModels<T>(T t, Expression<Func<T, object>> columns) where T : class, new()
        {
            return GetInstance().Update<T>().SetSource(t).UpdateColumns(columns).ExecuteAffrows();
            /*
             mo=new entity(){FontIcon=1,Icon=2,ID=1};
             FreeSqlHelper.UpdateModels(mo,p=>new {p.FontIcon,p.Icon })
             */
        }

        /// <summary>
        /// 根据主键更新实体(并忽略指定字段)，返回影响条数(实体字段要有主键特性)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="ignoreColumns">要忽略的字段</param>
        /// <returns></returns>
        public static int UpdateModels_Ignore<T>(T t, Expression<Func<T, object>> ignoreColumns) where T : class, new()
        {
            return GetInstance().Update<T>().SetSource(t).IgnoreColumns(ignoreColumns).ExecuteAffrows();
        }


        /// <summary>
        /// 动态更新
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="columns">要更新的字段</param>
        /// <param name="expressionWhere">条件表达式</param>
        /// <returns></returns>
        public static int Update<T>(Expression<Func<T, T>> columns, Expression<Func<T, bool>> expressionWhere) where T : class, new()
        {
            //这个方法也可以实现：GetInstance().Update<T>(expressionWhere).Set(columns).ExecuteAffrows();
            return GetInstance().Update<T>().Set(columns).Where(expressionWhere).ExecuteAffrows();
            // FreeSqlHelper.Update<SysPageModule>(p => new SysPageModule() {Icon = src}, p => p.ID.ToString() == id);
        }

        /*  update子查询。 注意freesql的Update方法只能单表操作。
                UPDATE SysModule
                    SET	
                         isend=0
                WHERE id=(SELECT parentID FROM SysModule AS sm WHERE sm.id=0)
            
            //多表update操作或update子查询，应该如下写法。
            int tempNum = db.Select<Entity.SysPageModule>()
                .Where(p => db.Select<Entity.SysPageModule>().Where(m => m.ID == id && p.ID == m.ParentID).Any())
                .ToUpdate()
                .Set(p => new Entity.SysPageModule() {IsLeaf = false})
                .ExecuteAffrows();
         */

        #endregion

        #region 删除方法 https://github.com/dotnetcore/FreeSql/wiki/%E5%88%A0%E9%99%A4

        /// <summary>
        /// 删除ids集合条件的字符串
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ids">ids为字符串 "1,2,3"或"1" 形式</param>
        /// <returns></returns>
        public static bool DeleteByIds<T>(string ids) where T : class, new()
        {
            var idList = GetLongListByString(ids);
            return GetInstance().Delete<T>(idList).ExecuteAffrows() > 0;
        }

        /// <summary>
        /// 根据条件表达式删除，返回影响条数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression">表达式</param>
        /// <returns></returns>
        public static int DeleteModels<T>(Expression<Func<T, bool>> expression) where T : class, new()
        {
            //此方法也可以实现 ：GetInstance().Delete<T>(expression).ExecuteAffrows();
            return GetInstance().Delete<T>().Where(expression).ExecuteAffrows();
        }

        #endregion

        #region ids转集合

        /// <summary>
        /// 将字符串转成int数组(, 号分割)
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public static int[] GetIntListByString(string ids)
        {
            if (string.IsNullOrWhiteSpace(ids)) return null;
            return Array.ConvertAll<string, int>(ids.Split(','), Int32.Parse);
        }

        /// <summary>
        /// 将字符串转成long数组(, 号分割)
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public static long[] GetLongListByString(string ids)
        {
            if (string.IsNullOrWhiteSpace(ids)) return null;
            return Array.ConvertAll<string, long>(ids.Split(','), Convert.ToInt64);
        }

        #endregion
    }
}
